/*
 Ajanta - Java Linear Programming Library

 Copyright 2010 Raghu Kaippully.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
package logic.simplex.model;

import java.util.*;

/**
 * A linear function used as the objective function in an {@link LPProblem}.
 * This can also be used as the left hand side of a constraint.
 */
public class LPFunction {

    /**
     * The terms in this function
     */
    private List<Term> terms = new ArrayList<Term>();
    /**
     * Collection of variables used in this function
     */
    private Set<LPVariable> variables = new HashSet<LPVariable>();

    /**
     * Adds a term to this function.
     *
     * @param coefficient the coefficient of the term
     * @param variable the LP variable of the term
     * @return this LP function
     * @throws IllegalArgumentException if variable is null or variable is
     * already used in another term of this function
     */
    public LPFunction plus(double coefficient, LPVariable variable) {
        synchronized (variables) {
            if (variable == null || variables.contains(variable)) {
                throw new IllegalArgumentException();
            }
            variables.add(variable);
            terms.add(new Term(coefficient, variable));
        }
        return this;
    }

    /**
     * Adds a term with a negative coefficient to this function.
     *
     * @param coefficient the coefficient of the term
     * @param variable the LP variable of the term
     * @return this LP function
     * @throws IllegalArgumentException if variable is null or variable is
     * already used in another term of this function
     */
    public LPFunction minus(double coefficient, LPVariable variable) {
        return plus(-coefficient, variable);
    }

    /**
     * Returns a set of all variables used in this function
     *
     * @return a set of all variables used in this function
     */
    public Set<LPVariable> getAllVariables() {
        return Collections.unmodifiableSet(variables);
    }

    /**
     * Returns the list of terms in this function
     *
     * @return a list of all terms used in this function
     */
    public List<Term> getTerms() {
        return Collections.unmodifiableList(terms);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Term t : terms) {
            if (sb.length() > 0) {
                sb.append(' ').append(t.coefficient < 0 ? "- " : "+ ");
            } else if (t.coefficient < 0) {
                sb.append("- ");
            }
            double val = Math.abs(t.coefficient);
            if (val != 1) {
                sb.append(val);
            }
            sb.append(t.variable);
        }
        return sb.toString();
    }
}
